﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
using System.Runtime.Remoting;

namespace ZPod.MTG.Communication.Remoting
{
	/// <summary>
	/// Cliente basado en Remoting
	/// ConnectionString: Machine|Port
	/// </summary>
	public class Client : BaseClient
	{
		/// <summary>
		/// Instancia remota del server
		/// </summary>
		private Server _connectedServer;

		private Server ConnectedServer
		{
			get
			{
				if (_connectedServer == null)
				{
					throw new NotConnectedException();
				}

				return _connectedServer;
			}
		}

		/// <summary>
		/// Canal TCP registrado
		/// </summary>
		private TcpChannel _channel;

		public override void Dispose()
		{
		}

		public override List<string> AvailableGames
		{
			get
			{
				return ConnectedServer.AvailableGames;
			}
		}

		public override GameState CurrentState
		{
			get
			{
				return ConnectedServer.GetGame(CurrentGame);
			}
		}

		public override void SetPlayerState(PlayerState state)
		{
			ConnectedServer.SetState(CurrentGame, PlayerName, state);
		}

		public override void Connect()
		{
			if (_connectedServer == null)
			{
				if (String.IsNullOrEmpty(ConnectionString))
				{
					throw new Exception("Falta ConnectionString");
				}

				var provider = new BinaryClientFormatterSinkProvider();
				
				_channel = new TcpChannel(null, provider, null);

				ChannelServices.RegisterChannel(_channel, false);

				// Obtengo la instancia del objeto remoto
				string serverAddress = GetServerAddress();
				Server server = (Server)Activator.GetObject(
					typeof(Server),
					serverAddress);

				// Si viene, me lo guardo
				if (server == null)
				{
					throw new RemotingException("Error: no se encuentra el servidor");
				}
				else
				{
					_connectedServer = server;
				}
			}
		}

		public override void CreateGame(string name)
		{
			ConnectedServer.CreateGame(name);
		}

		public override void Disconnect()
		{
			if (_channel != null)
			{
				ChannelServices.UnregisterChannel(_channel);
				_channel = null;
				_connectedServer = null;
			}
		}

		private string GetServerAddress()
		{
			if (String.IsNullOrEmpty(ConnectionString))
			{
				throw new Exception("Falta ConnectionString");
			}

			try
			{
				string[] parts = ConnectionString.Split('|');
				return String.Format("tcp://{0}:{1}{2}", parts[0], parts[1], parts[2]);
			}
			catch (Exception ex)
			{
				throw new Exception("Error al leer el ConnectionString. Su formato debe ser \"host|port|name\"", ex);
			}
		}

		public override void AddCommonCard(Card card)
		{
			ConnectedServer.AddCommonCard(CurrentGame, card);
		}

		public override void RemoveCommonCard(int index)
		{
			ConnectedServer.RemoveCommonCard(CurrentGame, index);
		}
	}
}
